Skip to content

Add new InputGroup compound component with Addon, Suffix, and Button support#249

Open
pedromenezes1 wants to merge 15 commits intocloudflare:mainfrom
pedromenezes1:feat/input-group-addon
Open

Add new InputGroup compound component with Addon, Suffix, and Button support#249
pedromenezes1 wants to merge 15 commits intocloudflare:mainfrom
pedromenezes1:feat/input-group-addon

Conversation

@pedromenezes1
Copy link
Contributor

@pedromenezes1 pedromenezes1 commented Mar 18, 2026

New InputGroup compound component for building inputs with icons, addons, inline suffixes, and action buttons.

Includes comprehensive documentation page with demos and unit tests.

Features

  • Field Integration — InputGroup accepts label, description, error, required, and labelTooltip props directly; automatically wraps in Field when label is provided
  • Addons — Place icons or text before/after the input using align="start" or align="end"
  • Compact Button — Small button inside an Addon for secondary actions (copy, clear, toggle visibility)
  • Action Button — Full-height flush button as a direct child for primary actions (submit, search)
  • Inline Suffix — Text that flows seamlessly next to the typed value (e.g., .workers.dev); input width adjusts automatically as user types
  • Size Variants — xs, sm, base, lg sizes cascade to all children via context
  • Error State — Error flows through context; InputGroup.Input auto-sets aria-invalid="true" when error is present
  • Disabled State — disabled prop disables all interactive children

Sub-components

Component Description
InputGroup Root container; provides context and accepts Field props
InputGroup.Input Styled input; inherits size, disabled, error from context
InputGroup.Addon Container for icons, text, or compact buttons; align="start" (default) or align="end"
InputGroup.Button Full-height button (direct child) or compact button (inside Addon)
InputGroup.Suffix Inline text suffix with automatic width measurement

Usage Examples

// With Field props (label, description, error, tooltip)
<InputGroup
  label="Email"
  description="We'll never share your email"
  error={{ message: "Invalid email", match: "typeMismatch" }}
  labelTooltip="Used for account recovery"
>
  <InputGroup.Input type="email" />
  <InputGroup.Addon align="end">@example.com</InputGroup.Addon>
</InputGroup>

// Inline suffix with auto-measuring width
<InputGroup>
  <InputGroup.Input placeholder="my-worker" />
  <InputGroup.Suffix>.workers.dev</InputGroup.Suffix>
</InputGroup>

// Search with icon addon and action button
<InputGroup>
  <InputGroup.Addon><MagnifyingGlassIcon /></InputGroup.Addon>
  <InputGroup.Input placeholder="Search..." />
  <InputGroup.Button variant="primary">Search</InputGroup.Button>
</InputGroup>

// Password with compact toggle button inside addon
<InputGroup label="Password">
  <InputGroup.Input type={show ? "text" : "password"} />
  <InputGroup.Addon align="end">
    <InputGroup.Button variant="ghost" size="sm" onClick={toggle}>
      {show ? <EyeSlashIcon /> : <EyeIcon />}
    </InputGroup.Button>
  </InputGroup.Addon>
</InputGroup>

Caveats

  • InputGroup.Input omits label, description, error, size, and labelTooltip props — these are handled by the parent InputGroup
  • When using InputGroup.Suffix, the input width is measured dynamically via a hidden ghost element
  • InputGroup.Button renders differently based on placement: full-height flush when direct child, compact when inside Addon

Screenshots

Screenshot 2026-03-18 at 14 13 05 Screenshot 2026-03-18 at 14 13 10 Screenshot 2026-03-18 at 14 13 13
Screenshot 2026-03-18 at 14 13 15 Screenshot 2026-03-18 at 14 13 18 Screenshot 2026-03-18 at 14 13 21
Screenshot 2026-03-18 at 14 13 25
Screenshot 2026-03-18 at 14 13 39 Screenshot 2026-03-18 at 14 13 42 Screenshot 2026-03-18 at 14 13 46
Screenshot 2026-03-18 at 14 13 50 Screenshot 2026-03-18 at 14 13 53 Screenshot 2026-03-18 at 14 13 59
Screenshot 2026-03-18 at 14 14 02

@pedromenezes1 pedromenezes1 force-pushed the feat/input-group-addon branch from b348d28 to 86e9d5d Compare March 18, 2026 01:38
@pedromenezes1 pedromenezes1 changed the title fix(InputGroup): flush button properly covers container ring border feat(InputGroup): revamp component with new compound API Mar 18, 2026
@pedromenezes1 pedromenezes1 changed the title feat(InputGroup): revamp component with new compound API feat: new InputGroup compound component with Addon, Suffix, and Button support Mar 18, 2026
@pedromenezes1 pedromenezes1 changed the title feat: new InputGroup compound component with Addon, Suffix, and Button support Add new InputGroup compound component with Addon, Suffix, and Button support Mar 18, 2026
@pedromenezes1 pedromenezes1 force-pushed the feat/input-group-addon branch 17 times, most recently from 1f88e51 to ca11f35 Compare March 18, 2026 14:10
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 18, 2026

npm i https://pkg.pr.new/@cloudflare/kumo@249

commit: e3556b6

@pedromenezes1 pedromenezes1 force-pushed the feat/input-group-addon branch from ca11f35 to 5c4d6f2 Compare March 18, 2026 14:12
@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

Docs Preview

View docs preview

Commit: e3556b6

@github-actions
Copy link
Contributor

github-actions bot commented Mar 18, 2026

Visual Regression Report

21 screenshot(s) with visual changes:

Button / Variants

3 px (0%) changed

Before After Diff
Before After Diff

Button / Sizes

6 px (0%) changed

Before After Diff
Before After Diff

Button / With Icon

51,698 px (1.77%) changed

Before After Diff
Before After Diff

Button / Icon Only

5 px (0%) changed

Before After Diff
Before After Diff

Button / Loading State

4 px (0%) changed

Before After Diff
Before After Diff

Button / Disabled State

4 px (0%) changed

Before After Diff
Before After Diff

Dialog / Basic Dialog

95,109 px (1.72%) changed

Before After Diff
Before After no diff

Dialog / Alert Dialog (role=“alertdialog”)

128,217 px (2.32%) changed

Before After Diff
Before After Diff

Dialog / Confirmation Dialog (with disablePointerDismissal)

20,161 px (0.36%) changed

Before After Diff
Before After Diff

Dialog / With Actions

137,099 px (2.48%) changed

Before After Diff
Before After Diff

Dialog / With Select

125,980 px (2.28%) changed

Before After Diff
Before After Diff

Dialog / With Combobox

159,863 px (2.89%) changed

Before After Diff
Before After Diff

Dialog / With Dropdown

149,829 px (2.71%) changed

Before After Diff
Before After Diff

Select / Basic Usage

11,446 px (1.95%) changed

Before After Diff
Before After Diff

Select / Without Visible Label

13,032 px (2.32%) changed

Before After Diff
Before After Diff

Select / With Description and Error

17,198 px (2.45%) changed

Before After Diff
Before After Diff

Select / Custom Rendering

45,217 px (2.72%) changed

Before After Diff
Before After Diff

Select / Loading

9,888 px (1.39%) changed

Before After Diff
Before After Diff

Select / Multiple Item

19,794 px (2.35%) changed

Before After Diff
Before After Diff

Select / Select

21,057 px (2.45%) changed

Before After Diff
Before After Diff

Select (Open)

0 px (0%) changed

Before After Diff
Before After Diff
5 screenshot(s) unchanged
  • Dialog (Open)
  • Select / Placeholder
  • Select / Label with Tooltip
  • Select / More Example
  • Select / Select.Option

Generated by Kumo Visual Regression

@mattrothenberg mattrothenberg force-pushed the feat/input-group-addon branch from 0caf233 to 5bbecc8 Compare March 18, 2026 14:40
@pedromenezes1 pedromenezes1 force-pushed the feat/input-group-addon branch from 92de07e to aa1cfae Compare March 19, 2026 14:31
pedromenezes1 and others added 3 commits March 19, 2026 14:49
…on support

New InputGroup compound component for building inputs with icons, addons, inline suffixes, and action buttons.

Features:
- Field Integration — Accepts label, description, error, required, and labelTooltip props
- Addons — Place icons or text before/after the input using align="start" or align="end"
- Compact Button — Small button inside an Addon for secondary actions
- Action Button — Full-height flush button as a direct child for primary actions
- Inline Suffix — Text that flows seamlessly next to the typed value
- Size Variants — xs, sm, base, lg sizes cascade to all children via context
- Error State — Error flows through context; InputGroup.Input auto-sets aria-invalid
- Disabled State — disabled prop disables all interactive children

Sub-components:
- InputGroup — Root container; provides context and accepts Field props
- InputGroup.Input — Styled input; inherits size, disabled, error from context
- InputGroup.Addon — Container for icons, text, or compact buttons
- InputGroup.Button — Full-height button (direct child) or compact button (inside Addon)
- InputGroup.Suffix — Inline text suffix with automatic width measurement

Includes comprehensive documentation page with demos and unit tests.
…on support

New InputGroup compound component for building inputs with icons, addons, inline suffixes, and action buttons.

Features:
- Field Integration — Accepts label, description, error, required, and labelTooltip props
- Addons — Place icons or text before/after the input using align="start" or align="end"
- Compact Button — Small button inside an Addon for secondary actions
- Action Button — Full-height flush button as a direct child for primary actions
- Inline Suffix — Text that flows seamlessly next to the typed value (uses CSS field-sizing)
- Size Variants — xs, sm, base, lg sizes cascade to all children via context
- Error State — Error flows through context; InputGroup.Input auto-sets aria-invalid
- Disabled State — disabled prop disables all interactive children

Sub-components:
- InputGroup — Root container; provides context and accepts Field props
- InputGroup.Input — Styled input; inherits size, disabled, error from context
- InputGroup.Addon — Container for icons, text, or compact buttons
- InputGroup.Button — Full-height button (direct child) or compact button (inside Addon)
- InputGroup.Suffix — Inline text suffix with CSS-based automatic width sizing

Includes comprehensive documentation page with demos and unit tests.
- Suppress outline on inner input with outline-none!
- Add has-[:focus-visible]:outline-auto to container in grouped mode
- When inner input receives keyboard focus, the native focus ring appears on the entire InputGroup container
- Uses browser's native -webkit-focus-ring-color for consistent appearance
- Fix addon padding with explicit pl-*/pr-* classes (Tailwind JIT compatible)
- Add type="button" to flush Button to prevent form submission
- Add forwardRef to InputGroup.Input for ref forwarding
- Add tests for error state (aria-invalid) and Field integration
- Update component registry with ring-kumo-line color token
- Revert flush button to render inside container (fixes focus ring issues)
- Make addon padding symmetric (start and end now match)
- Add forwardRef to InputGroup.Button for consistency
- Pass disabled state from context to Button
- Add tests for button variant and disabled state
- Fix stale JSDoc comment
- Use ring-0 instead of ring ring-transparent for clarity
@pedromenezes1 pedromenezes1 force-pushed the feat/input-group-addon branch from 141af9b to bf48d95 Compare March 19, 2026 14:51
pedromenezes1 and others added 7 commits March 19, 2026 14:55
- Add data-slot="input-group" for CSS targeting
- Remove overflow-visible rule for buttons (breaks clipping)
- Remove inline ring-transparent (was hiding focus ring)
- Add outline-none to inner input (prevent double outline)
- Let kumo-binding.css handle native outline
Match the docs format change from main (commit adfc9ab)
Resolve conflicts:
- SidebarNav.tsx: Add both InputArea and InputGroup entries
- HomeGrid.tsx: Add both input-area and input-group routes
- kumo-binding.css: Keep InputGroup focus ring CSS
- component-registry: Regenerate to include all components
Brings in Radio Card docs fix, Radio Object.assign fix, and version bumps.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants